package com.firexxx.vp.domain.vp;

import com.firexxx.vp.domain.audio.AudioEntity;
import com.firexxx.vp.domain.cluster.ClusterEngineFactory;
import com.firexxx.vp.domain.vp.fuse.FuseVoicePrintEntity;
import com.firexxx.vp.domain.vp.single.SingleVoicePrintEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: TODO
 * @throws:
 * @author: zhuangzhang2
 * @date: 2020/02/11 15:03
 */
@Service
@Slf4j
public class VoicePrintService {

    public VoicePrintModel match(@NotNull VoicePrintModel voicePrintModel,
                                      List<VoicePrintModel> voicePrintModelList, float scoreThreshold) {
        float maxScore = Float.MIN_VALUE;
        VoicePrintModel maxModel = null;

        for (VoicePrintModel item : voicePrintModelList) {
            float similarityScore = item.similarity(voicePrintModel);
            if (similarityScore >= scoreThreshold) {
                if (maxScore < similarityScore) {
                    maxModel = item;
                    maxScore = similarityScore;
                }
            }
        }

        return maxModel;
    }

    public List<FuseVoicePrintEntity> clusterByAudioGroup(String groupId, List<AudioEntity> audioEntityList) throws Throwable {
        List<List<AudioEntity>> audioClusterList = clusterAudioes(audioEntityList);

        if (audioClusterList.size() == 0) {
            return null;
        }

        List<FuseVoicePrintEntity> newFuseVoicePrintList = new ArrayList<>();

        for (List<AudioEntity> audioCluster : audioClusterList) {
            FuseVoicePrintEntity fuseVoicePrintEntity = fuseAudioes(groupId, audioCluster);
            if (fuseVoicePrintEntity != null) {
                newFuseVoicePrintList.add(fuseVoicePrintEntity);
            }
        }

        return newFuseVoicePrintList;
    }

    private List<List<AudioEntity>> clusterAudioes(List<AudioEntity> audioEntityList) throws Throwable {
        Map<String, String> vectorMap = new HashMap<>();
        Map<String, AudioEntity> entityMap = new HashMap<>();

        for (AudioEntity audioEntity : audioEntityList) {
            SingleVoicePrintEntity voicePrintEntity = new SingleVoicePrintEntity(audioEntity);

            try {
                voicePrintEntity.extractVoicePrint(VoicePrintResourceType.PNCC);
            } catch (Throwable t) {
                log.error("音频{}获取pncc声纹模型出错", audioEntity.getAudioId());

                throw t;
            }

            vectorMap.put(audioEntity.getAudioId(), voicePrintEntity.getVpModel().getVpModelEncrypted());
            entityMap.put(audioEntity.getAudioId(), audioEntity);
        }

        List<List<String>> results = ClusterEngineFactory.getInstance(VoicePrintResourceType.PNCC).clusterVector(vectorMap);
        List<List<AudioEntity>> entityResults = new ArrayList<>();
        for (List<String> list : results) {
            List<AudioEntity> entityList = new ArrayList<>();
            entityResults.add(entityList);

            for (String audioId : list) {
                entityList.add(entityMap.get(audioId));
            }
        }

        return entityResults;
    }

    public FuseVoicePrintEntity fuseAudioes(String groupId, List<AudioEntity> audioList) throws Throwable {
        FuseVoicePrintEntity fuseVoicePrintEntity = new FuseVoicePrintEntity(groupId, audioList);

        fuseVoicePrintEntity.fuseVoicePrint(VoicePrintResourceType.PLPPNCC);

        return fuseVoicePrintEntity;
    }

}